import pandas as pd
import matplotlib.pyplot as plt
Для этого урока используется набор данных air_quality_no2_long.csv
.
url = "https://raw.githubusercontent.com/dm-fedorov/pandas_basic/master/%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B5%20%D0%B2%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5%20%D0%B2%20pandas/data/air_quality_no2_long.csv"
air_quality = pd.read_csv(url)
air_quality = air_quality.rename(columns={"date.utc": "datetime"})
air_quality.head()
city | country | datetime | location | parameter | value | unit | |
---|---|---|---|---|---|---|---|
0 | Paris | FR | 2019-06-21 00:00:00+00:00 | FR04014 | no2 | 20.0 | µg/m³ |
1 | Paris | FR | 2019-06-20 23:00:00+00:00 | FR04014 | no2 | 21.8 | µg/m³ |
2 | Paris | FR | 2019-06-20 22:00:00+00:00 | FR04014 | no2 | 26.5 | µg/m³ |
3 | Paris | FR | 2019-06-20 21:00:00+00:00 | FR04014 | no2 | 24.9 | µg/m³ |
4 | Paris | FR | 2019-06-20 20:00:00+00:00 | FR04014 | no2 | 21.4 | µg/m³ |
air_quality.city.unique()
array(['Paris', 'Antwerpen', 'London'], dtype=object)
Я хочу работать с датами в столбце datetime
как объектами даты и времени вместо простого текста:
air_quality["datetime"] = pd.to_datetime(air_quality["datetime"])
air_quality["datetime"]
0 2019-06-21 00:00:00+00:00 1 2019-06-20 23:00:00+00:00 2 2019-06-20 22:00:00+00:00 3 2019-06-20 21:00:00+00:00 4 2019-06-20 20:00:00+00:00 ... 2063 2019-05-07 06:00:00+00:00 2064 2019-05-07 04:00:00+00:00 2065 2019-05-07 03:00:00+00:00 2066 2019-05-07 02:00:00+00:00 2067 2019-05-07 01:00:00+00:00 Name: datetime, Length: 2068, dtype: datetime64[ns, UTC]
Первоначально значения в datetime
являются символьными строками и не предоставляют никаких операций даты и времени (например, извлечение года, дня недели и т.д.). Применяя функцию to_datetime
, pandas интерпретирует строки и преобразует их в объекты datetime
(т.е. datetime64[ns, UTC]
). В pandas
мы называем эти объекты аналогично стандартной библиотеке datetime.datetime pandas.Timestamp
.
Поскольку многие наборы данных содержат информацию в формате datetime
в одном из столбцов, функции pandas.read_csv()
и pandas.read_json()
могут выполнить преобразование к датам в момент чтения данных через использование параметра parse_dates
:
pd.read_csv("../data/air_quality_no2_long.csv", parse_dates=["datetime"])
Какая польза от объектов pandas.Timestamp
?
С какой даты начинается и оканчивается набор данных?
air_quality["datetime"].min(), air_quality["datetime"].max()
(Timestamp('2019-05-07 01:00:00+0000', tz='UTC'), Timestamp('2019-06-21 00:00:00+0000', tz='UTC'))
Использование pandas.Timestamp
для datetime
позволяет нам производить расчеты с информацией о дате. Следовательно, мы можем использовать это, чтобы получить длину нашего временного ряда:
air_quality["datetime"].max() - air_quality["datetime"].min()
Timedelta('44 days 23:00:00')
В результате получается объект pandas.Timedelta
, аналогичный datetime.timedelta
в стандартной библиотеке Python и определяющий продолжительность времени.
Различные концепции времени, поддерживаемые pandas
, объясняются в разделе руководства пользователя о концепциях, связанных со временем.
Я хочу добавить новый столбец, содержащий только месяц измерения:
air_quality["month"] = air_quality["datetime"].dt.month
air_quality.head()
city | country | datetime | location | parameter | value | unit | month | |
---|---|---|---|---|---|---|---|---|
0 | Paris | FR | 2019-06-21 00:00:00+00:00 | FR04014 | no2 | 20.0 | µg/m³ | 6 |
1 | Paris | FR | 2019-06-20 23:00:00+00:00 | FR04014 | no2 | 21.8 | µg/m³ | 6 |
2 | Paris | FR | 2019-06-20 22:00:00+00:00 | FR04014 | no2 | 26.5 | µg/m³ | 6 |
3 | Paris | FR | 2019-06-20 21:00:00+00:00 | FR04014 | no2 | 24.9 | µg/m³ | 6 |
4 | Paris | FR | 2019-06-20 20:00:00+00:00 | FR04014 | no2 | 21.4 | µg/m³ | 6 |
Используя Timestamp
объекты, появляются многие связанные со временем свойства. Например month
, year
, weekofyear
, quarter
... Все эти свойства доступны по аксессору dt
.
Обзор существующих свойств даты приведен в таблице.
Какая средняя концентрация $NO_2$ для каждого дня недели и для каждого места измерения?
air_quality.groupby([air_quality["datetime"].dt.weekday, "location"])["value"].mean()
datetime location 0 BETR801 27.875000 FR04014 24.856250 London Westminster 23.969697 1 BETR801 22.214286 FR04014 30.999359 London Westminster 24.885714 2 BETR801 21.125000 FR04014 29.165753 London Westminster 23.460432 3 BETR801 27.500000 FR04014 28.600690 London Westminster 24.780142 4 BETR801 28.400000 FR04014 31.617986 London Westminster 26.446809 5 BETR801 33.500000 FR04014 25.266154 London Westminster 24.977612 6 BETR801 21.896552 FR04014 23.274306 London Westminster 24.859155 Name: value, dtype: float64
Здесь мы хотим вычислить статистику для каждого дня недели и для каждого места измерения. Для группировки по рабочим дням мы используем свойство weekday
(с Monday=0
и Sunday=6
) для Timestamp
, которое также доступно через dt
. Группировка по местоположениям и по дням недели выполняется, чтобы разделить вычисление среднего значения для каждой из этих комбинаций.
Типичный график для $NO_2$ в течение дня для всех станций. Другими словами, каково среднее значение для каждого часа дня?
fig, axs = plt.subplots(figsize=(12, 4))
air_quality.groupby(
air_quality["datetime"].dt.hour)["value"].mean().plot(kind='bar',
rot=0,
ax=axs)
plt.xlabel("Hour of the day"); # custom x label using matplotlib
plt.ylabel("$NO_2 (µg/m^3)$");
Как и в предыдущем случае, мы хотим вычислить данную статистику (например, среднее $NO_2$) для каждого часа дня, мы снова можем использовать метод разделения-применения-объединения.
pivot()
использовалось, чтобы изменить таблицу данных с каждым из мест измерений в качестве отдельной колонки:
no_2 = air_quality.pivot(index="datetime", columns="location", values="value")
no_2.head()
location | BETR801 | FR04014 | London Westminster |
---|---|---|---|
datetime | |||
2019-05-07 01:00:00+00:00 | 50.5 | 25.0 | 23.0 |
2019-05-07 02:00:00+00:00 | 45.0 | 27.7 | 19.0 |
2019-05-07 03:00:00+00:00 | NaN | 50.4 | 19.0 |
2019-05-07 04:00:00+00:00 | NaN | 61.9 | 16.0 |
2019-05-07 05:00:00+00:00 | NaN | 72.4 | NaN |
Поворачивая данные, информация о дате и времени стала индексом таблицы. Установка столбца в качестве индекса может быть достигнута функцией set_index
.
Работа с индексом datetime
(т.е. DatetimeIndex
) обеспечивает мощные возможности. Например, нам не нужен метод dt
для получения свойств временного ряда, но эти свойства доступны непосредственно в индексе:
no_2.index.year, no_2.index.weekday
(Int64Index([2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, ... 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019], dtype='int64', name='datetime', length=1033), Int64Index([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... 3, 3, 3, 3, 3, 3, 3, 3, 3, 4], dtype='int64', name='datetime', length=1033))
Существуют другие преимущества: удобное подмножество периода времени или адаптированный масштаб времени на графиках. Давайте применим это к нашим данным.
Построим график показаний $NO_2$ на разных станциях с 20 мая до конца 21 мая:
no_2["2019-05-20":"2019-05-21"].plot();
Предоставляя строку, которая анализирует дату и время, можно выбрать конкретное подмножество данных в DatetimeIndex
.
Более подробная информация о DatetimeIndex
приведена в разделе, посвященном индексированию временных рядов.
Объедините текущие значения часовых временных рядов с максимальным месячным значением на каждой из станций.
monthly_max = no_2.resample("M").max()
# https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.resample.html
monthly_max
location | BETR801 | FR04014 | London Westminster |
---|---|---|---|
datetime | |||
2019-05-31 00:00:00+00:00 | 74.5 | 97.0 | 97.0 |
2019-06-30 00:00:00+00:00 | 52.5 | 84.7 | 52.0 |
Очень мощный метод для временных рядов с индексом datetime
- это возможность создавать resample()
временные ряды с другой частотой (например, преобразовывать вторичные данные в данные за 5 минут).
Метод resample()
похож на операцию GroupBy
:
M
, 5H
...), что определяет целевую частотуmean
, max
...Обзор псевдонимов, используемых для определения частот временных рядов, приведен в таблице обзора псевдонимов смещения.
Когда определено, частота временного ряда обеспечена атрибутом freq
:
monthly_max.index.freq
<MonthEnd>
Постройте график ежедневной медианы значений $NO_2$ для каждой из станций.
no_2.resample("D").mean().plot(style="-o", figsize=(10, 5));
Более подробная информация о силе временных рядов resampling приведена в разделе инструкции пользователя на передискретизацию.
Полный обзор временных рядов приведен на страницах, посвященных временным рядам и функциям дат.
Подписка на онлайн-обучение